#pragma once

#include<cstring>
#include<iostream>
#include<assert.h>
using namespace std;
// 用命名空间封装，便于区分库里面的string
namespace Wang
{
class string
{
    public:
    size_t _size;       // 长度 
    size_t _capacity;   // 容量
    char* _str;         // 字符串
    static const size_t npos = -1;    // 按理说静态成员变量应该在类外初始化，但是被const修饰整数类型的是个特例，可以这样初始化
public:

    // 1.用C语言的字符串构造
    string(const char* s = "")
        :_size(strlen(s))   // 注意：初始化列表是按成员变量的声明顺序进行初始化，这里最好跟声明的顺序一致
        ,_capacity(_size)
        ,_str(new char[_capacity + 1])  // 要为'\0'留一个空间
    {
        strcpy(_str, s);    // 此函数会拷贝'\0'，记得 #include<cstring>
    }

    // 2.用n个字符c构造
    string (size_t n, char c)
        :_size(n)
        ,_capacity(n)
        ,_str(new char[n + 1])
    {
        memset(_str, c, sizeof(char) * n);  // memset是按字节初始化
        _str[n] = '\0';
    }

    string(const string& s)
        :_size(s._size)
        ,_capacity(_size)
        ,_str(new char[_size + 1])
    {
        strcpy(_str, s._str);
    }

    // string& operator= (const string& s)
    // {
    //     // 清理原有的内容
    //     delete[] _str;
    //     _str = new char[s._size + 1];
    //     _capacity = _size = s._size;
    //     strcpy(_str, s._str);
    //     return *this;
    // }

    string& operator= (const string& s)
    {
        string tmp(s);  // 将s拷贝到tmp
        swap(tmp);      // 交换*this与tmp
        return *this;   // 返回前顺便把tmp析构
    }

    ~string()
    {
        delete[] _str;
        _str = nullptr;
        _size = _capacity = 0;
    }
    // 提供c_str函数方便打印观察结果
    char* c_str() { return _str; }
    const char* c_str() const { return _str; }

    void swap(string& s)
    {
        std::swap(_str, s._str);
        std::swap(_size, s._size);
        std::swap(_capacity, s._capacity);
    }

    // 获取长度、容量
    size_t size() const { return _size; }
    size_t capacity() const { return _capacity; }

    // 扩容, 空间至少为n
    void reserve(size_t n)
    {
        if(n > _capacity)
        {
            char* t = new char[n + 1]; // 额外的'\0'
            strcpy(t, _str);
            delete[] _str;
            _str = t;
            _capacity = n;
        }
    }

    // 长度设为n
    void resize(size_t n)
    {
        if(n <= _size) _size = n;
        else{
            reserve(n);
            memset(&_str[_size], '\0', sizeof(char) * (n - _size)); // 默认用'\0'填充
            _size = n;
        }
        _str[_size] = '\0'; // 别忘了给结束位置设为'\0'
    }

    char& operator[](size_t pos)
    {
        assert(pos < _size);
        return _str[pos];
    }

    // 避免权限放大
    const char& operator[](size_t pos) const
    {
        assert(pos < _size);
        return _str[pos];
    }

    typedef char* iterator;
    typedef const char* const_iterator; // const对象的迭代器可以修改指向，不可修改指向的内容

    iterator begin() { return _str; }
    iterator end() { return _str + _size; }

    const_iterator begin() const { return _str; }
    const_iterator end() const { return _str + _size; }

    void push_back(char c)
    {
        if(_size == _capacity) // 空间满了扩容
            reserve(_capacity == 0 ? 4 : 2 * _capacity);
        _str[_size++] = c;
        _str[_size] = '\0';
    }

    // 尾插字符c
    string& operator+= (char c)
    {
        push_back(c);
        return *this;
    }
    // 尾插C语言类型字符串
    string& operator+= (const char* s)
    {
        int n = strlen(s);
        reserve(_size + n);
        // strcpy(_str + _size, s);
        // _size += n;
        for(int i = 0; i < n; i++)
            push_back(s[i]);
        return *this;
    }
    // 尾插string
    string& operator+= (const string& s)
    {
        *this += s.c_str();
        return *this;
    }

    // 在pos位置插入字符c
    string& insert(size_t pos, char c)
    {
        assert(pos <= _size);   // pos == _size相当于尾插
        if(_size == _capacity)
            reserve(_capacity == 0 ? 4 : 2*_capacity);
        memmove(&_str[pos + 1], &_str[pos], sizeof(char) * (_size - pos + 1)); // 尾部'\0'也顺便移动
        _str[pos] = c;
        _size++;
        return *this;
    }

    // 在pos位置插入C语言字符串s
    string& insert(size_t pos, const char* s)
    {
        assert(pos <= _size);   // pos == _size相当于尾插
        int n = strlen(s);
        reserve(_size + n);
        memmove(&_str[pos + n], &_str[pos], sizeof(char) * (_size - pos + 1));
        memcpy(&_str[pos], s, sizeof(char) * n);    //这里就不要用strcpy了，会把'\0'也拷贝进去
        _size += n;
        return *this;
    }

    // 在pos位置插入string
    string& insert(size_t pos, const string& s)
    {
        insert(pos, s.c_str());
        return *this;
    }

    void pop_back()
    {
        assert(_size != 0);
        --_size;
    }

    bool empty() const { return _size == 0; }
    char& front() 
    { 
        assert(_size != 0);
        return _str[0]; 
    }
    char& back() 
    { 
        assert(_size != 0);
        return _str[_size-1]; 
    }

    const char& front() const
    { 
        assert(_size != 0);
        return _str[0]; 
    }
    const char& back() const
    { 
        assert(_size != 0);
        return _str[_size-1]; 
    }

    string& erase(size_t pos = 0, size_t len = npos)
    {
        // 情况一：后面不足len个字符
        if(len > _size - pos) // 注意不要写成len + pos > _size，存在溢出风险
        { 
            _size = pos;
            _str[_size] = '\0';
        }
        else
            memmove(&_str[pos], &_str[pos + len], sizeof(char) * (_size - (pos + len) + 1));
        return *this;
    }
    void clear()
    {
        _size = 0;
        _str[0] = '\0';
    }
    // 从pos开始往后查找字符c，返回第一个找到的下标
    size_t find(char c, size_t pos = 0) const
    {
        for(int i = pos; i < _size; i++)
            if(_str[i] == c)
                return i;
        return npos;
    }

    // 从pos开始往后查找子串s，返回第一个找到的下标
    size_t find(const char* s, size_t pos = 0) const
    {
        int n = strlen(s);
        // 枚举以i为起点，能否匹配s串
        for(int i = pos; i < _size; i++)
        {
            int j = 0, k = i;
            for(; j < n && k < _size; j++, k++)
                if(s[j] != _str[k])
                    break;
            if(j == n) return i;
        }
        return npos;
    }
    size_t find(const string& s, size_t pos = 0) const
    {
        return find(s.c_str(), pos);
    }

    string substr(size_t pos = 0, size_t len = npos) const
    {
        assert(pos < _size);
        if(len > _size - pos) len = _size - pos;
        string res;
        res.reserve(len);
        for(int i = 0; i < len; i++)
            res += _str[pos + i];
        return res;
    }
};

ostream& operator<< (ostream& out, const string& s)
{
    out << s.c_str();
    return out;
}

istream& operator>> (istream& in, string& s)
{
    s.clear();
    char c = in.get(); // 相当于char c = getchar();
    while(c != ' ' && c != '\n' && c != '\t') // 遇到空白字符停下
    {
        s += c;
        c = in.get();
    }
    return in;
}

bool operator<(const string& s1, const string& s2)
{
    int i = 0, n1 = s1.size(), n2 = s2.size();
    const char* p1 = s1.c_str();
    const char* p2 = s2.c_str();
    for(; i <= n1 && i <= n2; i++) //算上最后的'\0'会简便一点
        if(p1[i] != p2[i])
            break;
    return p1[i] < p2[i];
}

bool operator== (const string& s1, const string& s2)
{
    if(s1.size() != s2.size()) return false;
    for(int i = 0; i < s1.size() && i < s2.size(); i++)
        if(s1[i] != s2[i]) 
            return false;
    return true;
}

bool operator> (const string& s1, const string& s2)
{
    int i = 0, n1 = s1.size(), n2 = s2.size();
    const char* p1 = s1.c_str();
    const char* p2 = s2.c_str();
    for(; i <= n1 && i <= n2; i++) //算上最后的'\0'会简便一点
        if(p1[i] != p2[i])
            break;
    return p1[i] > p2[i];
}

bool operator<= (const string& s1, const string& s2)
{
    return !(s1 > s2);
}

bool operator>= (const string& s1, const string& s2)
{
    return !(s1 < s2);
}
bool operator!= (const string& s1, const string& s2)
{
    return !(s1 == s2);
}

istream& getline(istream& in, string& s)
{
    s.clear();
    char c = in.get();
    while(c != '\n')
    {
        s += c;
        c = in.get();
    }
    return in;
}


}// namespace Wang